package com.gao.shiro.shiro;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gao.global.GlobalVariables;
import com.gao.modules.user.pojo.SysUser;
import com.gao.modules.user.service.SysUserService;
import com.gao.shiro.jwt.token.MyToken;
import com.gao.shiro.jwt.util.JwtUtil;
import com.gao.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;

/**
 * @Description TODO  自定义realm  实现登录功能的验证token以及进行授权
 * @Author anshenghui
 * @Date 2020/1/16 13:56
 * @Version 1.0
 */
@Slf4j
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private RedisUtil redisUtil;

//    @Autowired
//    private SysPermissionService sysPermissionService;

    //不添加此段代码会报错，还有可能不进入自定义的realm  不知道为什么
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof MyToken;
    }

    //执行认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("执行认证");
        String token = (String) authenticationToken.getCredentials();
        //校验token是否为空
        if (token == null && token.isEmpty()) {
            throw new AuthenticationException("token为空！！！");
        }
        String userName = "";
        SysUser sysUserEntity = null;
        UserModel userModel = null;
        //校验token是否正确，是否可以正常解析
        try {
            userName = JwtUtil.deCode(token);
        } catch (Exception e) {
            throw new AuthenticationException("token非法!!!");
        }
        if (userName.isEmpty()) {
            throw new AuthenticationException("token非法!!!");
        } else {
            //校验解析token的用户名是否存在  登录时主要是生成token   并且对用户名与密码做了校验
            // 在这里进行二次校验主要是为了防止随意一个可以解析的token都可以访问接口的情况出现，二次校验使接口更加安全
            sysUserEntity = sysUserService.getOne(new QueryWrapper<SysUser>().eq("user_name", userName));
            if (sysUserEntity == null) {
                throw new AuthenticationException("用户名不存在");
            } else {
                userModel = new UserModel(sysUserEntity);
            }
        }
        boolean flush = flushToken(userName, token, sysUserEntity.getPassword());
        if (!flush) {
            throw new AuthenticationException("token为空，请重新登录");
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userModel, token, userName);
        return simpleAuthenticationInfo;
    }

    //执行授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        log.info("执行授权");
        UserModel userModel = (UserModel) principalCollection.getPrimaryPrincipal();
//        if (userModel != null) {
//            String userName = userModel.getUsername();
//            Set<String> roleSet = sysUserService.getRoleCodeByUserName(userName);
//            simpleAuthorizationInfo.setRoles(roleSet);
//            Set<String> permissionSet = sysPermissionService.getPermissionCodeByUserName(userName);
//            if (!permissionSet.isEmpty()) {
//                simpleAuthorizationInfo.setStringPermissions(permissionSet);
//            }
//        }
        return simpleAuthorizationInfo;
    }

    //刷新token
    private boolean flushToken(String userName, String token, String passWord) {
        //response不作为入参进行获取相应response
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String redisToken = (String) redisUtil.get(GlobalVariables.PREFIX_TOKEN + token);
        //如果redis里面的token不为空，那么就代表登录了  如果redis里面没有token那么就必须重新登陆
        if (!redisToken.isEmpty()) {
            //查看jwtToken是否有效
            //如果jwtToekn失效了,但是缓存中存在token，所以用户是一直在线的
            if (!JwtUtil.checkToken(token, userName, passWord)) {
                //重新生成token，并且放入相应头返回给前端  更新redis
                String newToken = JwtUtil.createToken(userName, passWord);
                response.setHeader(GlobalVariables.HEADER_TOKEN, newToken);
                redisUtil.delete(Arrays.asList((GlobalVariables.PREFIX_TOKEN + token)));
                redisUtil.setCommons((GlobalVariables.PREFIX_TOKEN + newToken), newToken, GlobalVariables.TOKEN_CACHE);
            } else {
                //如果都没有过期  那么直接刷新redis里面的数据
                redisUtil.setCommons((GlobalVariables.PREFIX_TOKEN + token), token, GlobalVariables.TOKEN_CACHE);
            }
            return true;
        }
        return false;
    }
}
